improve correctness and speed of duplicate filter. (#1144)
authortsteven4 <13596209+tsteven4@users.noreply.github.com>
Tue, 25 Jul 2023 00:28:23 +0000 (18:28 -0600)
committerGitHub <noreply@github.com>
Tue, 25 Jul 2023 00:28:23 +0000 (18:28 -0600)
* improve correctness and speed of duplicate filter.

The duplicate filter could errouneously delete points that were
not duplicates if the crc's happened to match.

waypt_del(Waypoint*) is inefficent as it requires a search of the
list to find the matching waypoint.  Support waypt_del with iterators.

* retire util_crc.cc

* improve duplicate to linear complexity

* polish new list creation.

* Remove final remnants of 'exported'

* Revert "Remove final remnants of 'exported'"

This reverts commit 6996e4d7dd4b1812f922edd2c5bd9a3d1bc6fada.

---------

Co-authored-by: Robert Lipe <robertlipe@gmail.com>
CMakeLists.txt
defs.h
deprecated/util_crc.cc [new file with mode: 0644]
duplicate.cc
duplicate.h
util_crc.cc [deleted file]
xmldoc/filters/duplicate.xml

index 14eb5ca7a2bd923c0046b4c62cd5f78dd8807d1d..465b00573d2d2de431099edaedc4e3e51b5d2f4e 100644 (file)
@@ -182,7 +182,6 @@ set(SUPPORT
   src/core/xmltag.cc
   units.cc
   util.cc
-  util_crc.cc
   vecs.cc
   waypt.cc
   xmlgeneric.cc
diff --git a/defs.h b/defs.h
index f417e52b05f987211e55db712b2b8b5fe09fb534..635f5ae12df5fe2cedfeed136f084d67d27c92c6 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -492,6 +492,7 @@ public:
   void waypt_del(Waypoint* wpt); // a.k.a. erase()
   // FIXME: Generally it is inefficient to use an element pointer or reference to define the element to be deleted, use iterator instead,
   //        and/or implement pop_back() a.k.a. removeLast(), and/or pop_front() a.k.a. removeFirst().
+  iterator waypt_del(iterator it) {return erase(it);}
   void del_rte_waypt(Waypoint* wpt);
   void waypt_compute_bounds(bounds* bounds) const;
   Waypoint* find_waypt_by_name(const QString& name) const;
@@ -1110,11 +1111,6 @@ int parse_distance(const QString& str, double* val, double scale, const char* mo
 int parse_speed(const char* str, double* val, double scale, const char* module);
 int parse_speed(const QString& str, double* val, double scale, const char* module);
 
-/*
- *  From util_crc.c
- */
-unsigned long get_crc32(const void* data, int datalen);
-
 /*
  * Color helpers.
  */
diff --git a/deprecated/util_crc.cc b/deprecated/util_crc.cc
new file mode 100644 (file)
index 0000000..068d7db
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+    Compute CRC32's.
+
+    Copyright (C) 2002, 2003, 2004 Robert Lipe, robertlipe+source@gpsbabel.org
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ */
+
+static unsigned long crc32_table[256] = {
+  0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
+  0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+  0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
+  0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+  0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+  0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+  0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
+  0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+  0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
+  0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+  0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
+  0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+  0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
+  0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+  0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
+  0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+  0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
+  0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+  0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
+  0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+  0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
+  0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+  0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
+  0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+  0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+  0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+  0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
+  0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+  0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
+  0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+  0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
+  0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+  0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
+  0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+  0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+  0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+  0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
+  0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+  0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
+  0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+  0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
+  0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+  0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+unsigned long
+get_crc32(const void* data, int datalen)
+{
+  unsigned long crc = 0xFFFFFFFF;
+  const auto* cp = static_cast<const unsigned char*>(data);
+
+  while (cp < (static_cast<const unsigned char*>(data) + datalen)) {
+    crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32_table[(crc ^ *cp) &0xFF];
+    cp++;
+  }
+
+  return (crc ^ 0xFFFFFFFF);
+}
index 82f1eb929a198d193ccb269b2a0b37cbd3b529c2..fb471154c261977591b7aa5cc08b784c15f7f74d 100644 (file)
@@ -1,7 +1,7 @@
 /*
     exact duplicate point filter utility.
 
-    Copyright (C) 2002-2014 Robert Lipe, robertlipe+source@gpsbabel.org
+    Copyright (C) 2002-2023 Robert Lipe, robertlipe+source@gpsbabel.org
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 #include "duplicate.h"
 
 #include <algorithm>             // for stable_sort
-#include <cstdio>                // for snprintf
-#include <cstring>               // for memset, strncpy
 
 #include <QDateTime>             // for QDateTime
+#include <QList>                 // for QList, QList<>::iterator, QList<>::const_iterator
+#include <QMultiHash>            // for QMultiHash
 
 #include "defs.h"
 #include "geocache.h"            // for Geocache
 
 #if FILTERS_ENABLED
 
-DuplicateFilter::btree_node* DuplicateFilter::addnode(btree_node* tree, btree_node* newnode, btree_node** oldnode)
-{
-  btree_node* last = nullptr;
-
-  if (*oldnode) {
-    *oldnode = nullptr;
-  }
-
-  if (!tree) {
-    return (newnode);
-  }
-
-  btree_node* tmp = tree;
-
-  while (tmp) {
-    last = tmp;
-    if (newnode->data < tmp->data) {
-      tmp = tmp->right;
-    } else if (newnode->data > tmp->data) {
-      tmp = tmp->left;
-    } else {
-      if (oldnode) {
-        *oldnode = tmp;
-      }
-      return (nullptr);
-    }
-  }
-
-  if (newnode->data < last->data) {
-    last->right = newnode;
-  } else {
-    last->left = newnode;
-  }
-
-  return (tree);
-}
-
-void DuplicateFilter::free_tree(btree_node* tree)
-{
-  if (tree->left) {
-    free_tree(tree->left);
-  }
-  if (tree->right) {
-    free_tree(tree->right);
-  }
-  xfree(tree);
-}
-
+#define MYNAME "duplicate"
 /*
 
 It looks odd that we have different comparisons for date and index.
@@ -111,83 +64,79 @@ one with the smaller index (i.e. the first of those two points that we
 came across while importing waypoints.)
 
 In the (common) case that we have no exported dates, the dates will all
-be zero so the sort will end up being an expensive no-op (expensive
-because, sadly, quicksort can be O(n^2) on presorted elements.)
+be zero so the sort will end up being an expensive no-op.  However, the
+complexity of this filter is dominated by other concerns.
 */
 
+void DuplicateFilter::init()
+{
+  if (!lcopt && !snopt) {
+    fatal(MYNAME ": one or both of the shortname and location options are required.\n");
+  }
+}
+
 void DuplicateFilter::process()
 {
-  btree_node* btmp = nullptr;
-  btree_node* sup_tree = nullptr;
-  btree_node* oldnode = nullptr;
-  struct {
-    char shortname[32];
-    char lat[13];
-    char lon[13];
-  } dupe;
-  Waypoint* delwpt = nullptr;
-
-  auto htable = *global_waypoint_list;
+  int delete_flag; // &delete_flag != nullptr
+
+  auto wptlist = *global_waypoint_list;
 
   auto compare_lambda = [](const Waypoint* wa, const Waypoint* wb)->bool {
     return wa->gc_data->exported > wb->gc_data->exported;
   };
-  std::stable_sort(htable.begin(), htable.end(), compare_lambda);
+  std::stable_sort(wptlist.begin(), wptlist.end(), compare_lambda);
 
-  for (Waypoint* waypointp : htable) {
-
-    memset(&dupe, '\0', sizeof(dupe));
-
-    if (snopt) {
-      strncpy(dupe.shortname, CSTRc(waypointp->shortname), sizeof(dupe.shortname) - 1);
-    }
+  QMultiHash<QString, Waypoint*> wpthash;
+  for (Waypoint* waypointp : wptlist) {
+    waypointp->extra_data = nullptr;
 
+    QString key;
     if (lcopt) {
       /* The degrees2ddmm stuff is a feeble attempt to
        * get everything rounded the same way in a precision
        * that's "close enough" for determining duplicates.
        */
-      snprintf(dupe.lat, sizeof(dupe.lat), "%11.3f",
-               degrees2ddmm(waypointp->latitude));
-      snprintf(dupe.lon, sizeof(dupe.lon), "%11.3f",
-               degrees2ddmm(waypointp->longitude));
-
+      key = QStringLiteral("%1%2")
+        .arg(degrees2ddmm(waypointp->latitude), 11, 'f', 3)
+        .arg(degrees2ddmm(waypointp->longitude), 11, 'f', 3);
+    }
+  
+    if (snopt) {
+      key.append(waypointp->shortname);
     }
 
-    unsigned long crc = get_crc32(&dupe, sizeof(dupe));
-
-    auto* newnode = (btree_node*)xcalloc(sizeof(btree_node), 1);
-    newnode->data = crc;
-    newnode->wpt = waypointp;
-
-    btmp = addnode(sup_tree, newnode, &oldnode);
+    wpthash.insert(key, waypointp);
+  }
 
-    if (btmp == nullptr) {
-      delete delwpt;
-      if (correct_coords && oldnode && oldnode->wpt) {
-        oldnode->wpt->latitude = waypointp->latitude;
-        oldnode->wpt->longitude = waypointp->longitude;
+  const QList<QString> keys = wpthash.uniqueKeys();
+  for (const auto& key : keys) {
+    const QList<Waypoint*> values = wpthash.values(key);
+    if (values.size() > 1) {
+      Waypoint* wptfirst = values.last(); // first inserted
+      if (correct_coords) {
+        Waypoint* wptlast = values.front(); // last inserted
+        wptfirst->latitude = wptlast->latitude;
+        wptfirst->longitude = wptlast->longitude;
       }
-      delwpt = waypointp;
-      waypt_del(waypointp); /* collision */
-      xfree(newnode);
-      if (purge_duplicates && oldnode) {
-        if (oldnode->wpt) {
-          waypt_del(oldnode->wpt);
-          delete oldnode->wpt;
-          oldnode->wpt = nullptr;
+      for (auto it = values.cbegin(); it != values.cend(); ++it) {
+        Waypoint* wpt = *it;
+        if (purge_duplicates || (wpt != wptfirst)) {
+          wpt->extra_data = &delete_flag;
         }
       }
-
-    } else {
-      sup_tree = btmp;
     }
   }
 
-  delete delwpt;
-
-  if (sup_tree) {
-    free_tree(sup_tree);
+  // For lineary complexity build a new list from the points we keep.
+  WaypointList oldlist;
+  waypt_swap(oldlist);
+  
+  for (Waypoint* wpt : qAsConst(oldlist)) {
+    if (wpt->extra_data == nullptr) {
+      waypt_add(wpt);
+    } else {
+      delete wpt;
+    }
   }
 }
 
index 0fd5f85cad64205928ab0ce70e219ece6626cab4..d8d165209ca75fb87049103a7e317ba12cda77e6 100644 (file)
@@ -1,7 +1,7 @@
 /*
     exact duplicate point filter utility.
 
-    Copyright (C) 2002-2014 Robert Lipe, robertlipe+source@gpsbabel.org
+    Copyright (C) 2002-2023 Robert Lipe, robertlipe+source@gpsbabel.org
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -37,6 +37,7 @@ public:
   {
     return &args;
   }
+  void init() override;
   void process() override;
 
 private:
@@ -64,16 +65,6 @@ private:
     },
   };
 
-  struct btree_node {
-    btree_node* left;
-    btree_node* right;
-    unsigned long data;
-    Waypoint* wpt;
-  };
-
-  static btree_node* addnode(btree_node* tree, btree_node* newnode, btree_node** oldnode);
-  void free_tree(btree_node* tree);
-
 };
 #endif
 #endif // DUPLICATE_H_INCLUDED_
diff --git a/util_crc.cc b/util_crc.cc
deleted file mode 100644 (file)
index 068d7db..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-    Compute CRC32's.
-
-    Copyright (C) 2002, 2003, 2004 Robert Lipe, robertlipe+source@gpsbabel.org
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
- */
-
-static unsigned long crc32_table[256] = {
-  0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
-  0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
-  0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
-  0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
-  0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
-  0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
-  0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
-  0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
-  0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
-  0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
-  0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
-  0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
-  0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
-  0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
-  0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
-  0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
-  0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
-  0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
-  0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
-  0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
-  0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
-  0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
-  0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
-  0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
-  0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
-  0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
-  0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
-  0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
-  0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
-  0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
-  0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
-  0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
-  0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
-  0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
-  0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
-  0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
-  0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
-  0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
-  0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
-  0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
-  0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
-  0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
-  0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
-};
-
-unsigned long
-get_crc32(const void* data, int datalen)
-{
-  unsigned long crc = 0xFFFFFFFF;
-  const auto* cp = static_cast<const unsigned char*>(data);
-
-  while (cp < (static_cast<const unsigned char*>(data) + datalen)) {
-    crc = ((crc >> 8) & 0x00FFFFFF) ^ crc32_table[(crc ^ *cp) &0xFF];
-    cp++;
-  }
-
-  return (crc ^ 0xFFFFFFFF);
-}
index 922522f492d1a7877bfcfbac119d58668cc4f698..9ef4d4be72adc7b6c738d9c6ce7520ddf59f7e5f 100644 (file)
@@ -4,7 +4,7 @@ short name (traditionally a waypoint's name on the GPS receiver), and/or
 their location (to a  precision of 6 decimals).  This filter supports two
 options that specify how duplicates will be recognized,
 <option>shortname</option> and <option>location</option>.
-Generally, at least one of these options is required.
+At least one of these options is required.
 </para>
 <example xml:id="duplicate_to_suppress_points">
   <title>Using the duplicate filter to suppress points with the same